package de.akabahn.ebd.stw.zdxfc.prs.commande;

import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT0;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT1;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BLOCK_1231;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BLOCK_1231_ANNONCE;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BLOCK_1231_MELDER_VL;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BLOCK_1231_SONNERIE;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.MELDER_SIGNAL_S4880;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.SCHALTER_PREFIX;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.SPERRE_ZDXFC;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.TASTE_PREFIX;

import javax.sound.sampled.Clip;

import org.apache.log4j.Logger;

import de.akabahn.ebd.comm.dbd.DBDParameter;
import de.akabahn.ebd.dbd.DBDSubscriptionListener;
import de.akabahn.ebd.stw.zdxfc.prs.commande.elemente.KontrollLampe;
import de.akabahn.ebd.stw.zdxfc.prs.commande.elemente.Schalter;
import de.akabahn.ebd.stw.zdxfc.prs.commande.elemente.Taste;

/**
 * Implementierung des <code>DBDSubscriptionListener</code> interfaces fuer die zentrale Verwaltung der
 * Aenderungen an den abonnierten Variablen.
 * 
 * @author Peter Eimann
 * @since 1.0
 * @version 1.2
 */
public class ZDXFCCommandeDispatcher implements DBDSubscriptionListener {

	private final static Logger LOG = Logger.getLogger(ZDXFCCommandeDispatcher.class);

	private ZDXFCCommandeMain main;

	/**
	 * Initialisierung der Klasse
	 * 
	 * @param main Referenz auf die Hauptklasse
	 */
	public ZDXFCCommandeDispatcher(ZDXFCCommandeMain main) {
		this.main = main;
	}
	
	/**
	 * Diese Methode wird vom DBD-Adapter aufgerufen, wenn sich der Wert einer abonnierten Variable
	 * geaendert hat.<br>
	 * Innerhalb der Methode wird ausgewertet, welche Variable sich geaendert hat, um die entsprechende Methode
	 * zur Behandlung der Aenderung aufzurufen:<br>
	 * <ol>
	 * <li>Kontroll-Lampe: <code>onChangeKontrollLampe(dbd)</code></li>
	 * <li>Sperre: <code>onChangeSperre(dbd)</code>
	 * <li>Schalterausleuchtung: <code>onChangeMelderSchalter(dbd)</code></li>
	 * <li>Tastenausleuchtung: <code>onChangeMelderTaste(dbd)</code></li>
	 * <li>Sound: <code>onChangeSound(dbd)</code></li>
	 * </ol>
	 * 
	 * @param dbd Die geaenderte Variable
	 * @see DBDParameter
	 * @see #onChangeKontrollLampe(DBDParameter)
	 * @see #onChangeSperre(DBDParameter)
	 * @see #onChangeMelderSchalter(DBDParameter)
	 * @see #onChangeMelderTaste(DBDParameter)
	 * @see #onChangeSound(DBDParameter)
	 */
	@Override
	public synchronized void onChange(DBDParameter dbd) {
		LOG.debug("onChange: " + dbd.toString());

		if (dbd.getName().equals(MELDER_SIGNAL_S4880[0]) || dbd.getName().equals(BLOCK_1231_MELDER_VL)) {
			onChangeKontrollLampe(dbd);
		} else if (dbd.getName().equals(SPERRE_ZDXFC)) {
			onChangeSperre(dbd);
		} else if (dbd.getName().startsWith(SCHALTER_PREFIX)) {
			onChangeMelderSchalter(dbd);
		} else if (dbd.getName().startsWith(TASTE_PREFIX)) {
			onChangeMelderTaste(dbd);
		} else if (dbd.getName().startsWith(BLOCK_1231)) {
			onChangeSound(dbd);
		}
	}
	
	/**
	 * Die Ausleuchtung einer Kontroll-Lampe hat sich geaendert:
	 * <ul>
	 * <li>Wert der DBD-Variablen ist 1: Aufruf von <code>Kontrolllampe.kontrollLampeAn()</code></li>
	 * <li>Ansonsten: Aufruf von <code>Kontrolllampe.kontrollLampeAus()</code></li>
	 * </ul>
	 * 
	 * @param dbd Die geaenderte Variable
	 * @see KontrollLampe#kontrollLampeAn()
	 * @see KontrollLampe#kontrollLampeAus()
	 */
	private void onChangeKontrollLampe(DBDParameter dbd) {
		LOG.debug("onChangeKontrollLampe: " + dbd.toString());
		
		if ((dbd.getValue() & BIT0) == BIT0) {
			main.getKontrolllampe(dbd.getName()).kontrollLampeAn();
		} else {
			main.getKontrolllampe(dbd.getName()).kontrollLampeAus();
		}
	}
	
	/**
	 * Die Ausleuchtung eines Schalters hat sich geaendert:
	 * <ul>
	 * <li>Wert der DBD-Variablen ist 1: Aufruf von <code>Schalter.ausleuchtungAn()</code></li>
	 * <li>Ansonsten: Aufruf von <code>Schalter.ausleuchtungAus()</code></li>
	 * </ul>
	 * 
	 * @param dbd Die geaenderte Variable
	 * @see Schalter#ausleuchtungAn()
	 * @see Schalter#ausleuchtungAus()
	 */
	private void onChangeMelderSchalter(DBDParameter dbd) {
		LOG.debug("onChangeMelderSchalter: " + dbd.toString());
		
		String schalterId = dbd.getName().substring(0, dbd.getName().length() - 1) + "I";
		if ((dbd.getValue() & BIT0) == BIT0) {
			main.getSchalter(schalterId).ausleuchtungAn();
		} else {
			main.getSchalter(schalterId).ausleuchtungAus();
		}
	}
	
	/**
	 * Die Ausleuchtung einer Taste hat sich geaendert:
	 * <ul>
	 * <li>Wert der DBD-Variablen ist 2: Aufruf von <code>Taste.ausleuchtungBlinkt()</code></li>
	 * <li>Wert der DBD-Variablen ist 1: Aufruf von <code>Taste.ausleuchtungAn()</code></li>
	 * <li>Ansonsten: Aufruf von <code>Taste.ausleuchtungAus()</code></li>
	 * </ul>
	 * 
	 * @param dbd Die geaenderte Variable
	 * @see Taste#ausleuchtungBlinkt()
	 * @see Taste#ausleuchtungAn()
	 * @see Taste#ausleuchtungAus()
	 */
	private void onChangeMelderTaste(DBDParameter dbd) {
		LOG.debug("onChangeMelderTaste: " + dbd.toString());
		
		String tastenId = dbd.getName().substring(0, dbd.getName().length() - 1) + "I";
		if ((dbd.getValue() & BIT1) == BIT1) {
			main.getTaste(tastenId).ausleuchtungBlinkt();
		} else if ((dbd.getValue() & BIT0) == BIT0) {
			main.getTaste(tastenId).ausleuchtungAn();
		} else {
			main.getTaste(tastenId).ausleuchtungAus();
		}
	}
	
	/**
	 * Ein Sound-Flag hat sich geaendert:
	 * <ul>
	 * <li>Annonce-Sound: Abspielen des Annonce-Sounds und Zuruecksetzen der DBD-Variablen auf 0</li>
	 * <li>Sonnerie-Sound: Abspielen des Sonnerie-Sounds (Wert 1) oder Stoppen des Sounds (Wert 0)</li>
	 * </ul>
	 * 
	 * @param dbd Die geaenderte Variable
	 */
	private void onChangeSound(DBDParameter dbd) {
		LOG.debug("onChangeSound: " + dbd.toString());

		if (BLOCK_1231_ANNONCE.equals(dbd.getName())) {
			if (dbd.getValue() == 1) {
				main.getAnnonceClip().stop();
				main.getAnnonceClip().setFramePosition(0);
				main.getAnnonceClip().start();
				main.getDbd().set(BLOCK_1231_ANNONCE, 0);
			}
		} else if (BLOCK_1231_SONNERIE.equals(dbd.getName())) {
			if (dbd.getValue() == 0) {
				main.getSonnerieClip().stop();
			} else {
				main.getSonnerieClip().setFramePosition(0);
				main.getSonnerieClip().loop(Clip.LOOP_CONTINUOUSLY);
				main.getSonnerieClip().start();
			}
		}
	}

	/**
	 * @param enabled
	 */
	private void onChangeSperre(DBDParameter dbd) {
		boolean enabled = dbd.getValue() == 0;

		for (String key : main.getSchalter().keySet()) {
			main.getSchalter(key).setEnabled(enabled);
		}
		for (String key : main.getTasten().keySet()) {
			main.getTaste(key).setEnabled(enabled);
		}
	}
}
